﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lizk.WebScraper;
using MediaData;

namespace SharpMedia
{
    public class ScraperHandler
    {
        private Dictionary<MediaDataSet.TitlesRow, ScraperState> activeScrapes = new Dictionary<MediaDataSet.TitlesRow, ScraperState>();
        private Dictionary<string, string> scraperTypes = new Dictionary<string, string>();


        public ScraperHandler(params MediaCategory[] settings)
        {
            foreach (var set in settings)
            {
                scraperTypes.Add(set.Name, set.ScraperClass);
            }
        }

        public class ScraperStatusArgs : EventArgs
        {
            public ScraperState Result { get; set; }
            public ScraperStatusArgs(ScraperState state)
            {
                this.Result = state;
            }
        }

        public event EventHandler<ScraperStatusArgs> ScrapeComplete;

        public void Scrape(MediaDataSet.TitlesRow title) { Scrape(title, title.Name); }
        public void ScrapeInfo(MediaDataSet.TitlesRow title, ScraperResult searchResult)
        {
            if (!activeScrapes.ContainsKey(title) || activeScrapes[title].Status == ScraperStatus.InProgress)
                return;

            activeScrapes[title].Status = ScraperStatus.InProgress;
            activeScrapes[title].Scraper.BeginGetInfo(searchResult.ID);

        }

        public void Scrape(MediaDataSet.TitlesRow title, string searchString)
        {
            //SharpMedia.ScraperHandler.Scrape(title);
            if (activeScrapes.ContainsKey(title) && activeScrapes[title].Status == ScraperStatus.InProgress)
                return;

            string scraperType;
            if (!scraperTypes.TryGetValue(title.Type, out scraperType))
                return;

            Scraper s = Scraper.GetScraperInstance(scraperType);
            if (s == null)
                return;

            s.ProgressUpdated += new System.EventHandler<ScraperEventArgs>(s_ProgressUpdated);
            s.ScapeCompleted += new System.EventHandler<ScrapeEndResultArgs>(s_ScapeCompleted);
            s.SearchCompleted += new System.EventHandler<ScaperSearchArgs>(s_SearchCompleted);
            s.Tag = title;

            if (!activeScrapes.ContainsKey(title))
            {
                activeScrapes.Add(title, new ScraperState(s, title, ScraperStatus.InProgress));
            }
            else
            {
                activeScrapes[title].Scraper = s;
                activeScrapes[title].Status = ScraperStatus.InProgress;
            }
            s.BeginSearch(searchString);
        }


        void s_SearchCompleted(object sender, ScaperSearchArgs e)
        {
            Scraper s = (Scraper)sender;
            MediaDataSet.TitlesRow title = (MediaDataSet.TitlesRow)s.Tag;
            
            if (!activeScrapes.ContainsKey(title))
                return;

            bool resultsFound = false;
            foreach (ScraperResult result in e.ResultsFound)
            {
                resultsFound = true;
            }

            if (resultsFound)
            {
                activeScrapes[title].Status = ScraperStatus.MultipleResults;
                activeScrapes[title].Results = new List<ScraperResult>(e.ResultsFound).ToArray();
            }
            else
            {
                activeScrapes[title].Status = ScraperStatus.Error;
                activeScrapes[title].ErrorMessage = "No results found!";
            }
        }

        void s_ScapeCompleted(object sender, ScrapeEndResultArgs e)
        {
            Scraper s = (Scraper)sender;
            MediaDataSet.TitlesRow title = (MediaDataSet.TitlesRow)s.Tag;
            if (!activeScrapes.ContainsKey(title))
                return;

            if (e.Result == null)
            {
                activeScrapes[title].Status = ScraperStatus.Error;
                activeScrapes[title].ErrorMessage = "No result found";
                return;
            }

            activeScrapes[title].Status = ScraperStatus.Done;

            if (e.Result != null && ScrapeComplete != null)
            {
                activeScrapes[title].Results = new ScraperResult[] { e.Result };
                ScrapeComplete(this, new ScraperStatusArgs(activeScrapes[title]));
            }
            activeScrapes.Remove(title);
        }

        void s_ProgressUpdated(object sender, ScraperEventArgs e)
        {
            Scraper s = (Scraper)sender;
            MediaDataSet.TitlesRow title = (MediaDataSet.TitlesRow)s.Tag;
            if (!activeScrapes.ContainsKey(title))
                return;
            switch (e.Status)
            {
                case ScraperEventArgs.ScaperStatus.Idle:
                    break;
                case ScraperEventArgs.ScaperStatus.Connecting:
                    break;
                case ScraperEventArgs.ScaperStatus.Downloading:
                    break;
                case ScraperEventArgs.ScaperStatus.Done:
                    break;
                case ScraperEventArgs.ScaperStatus.Error:
                    activeScrapes[title].Status = ScraperStatus.Error;
                    activeScrapes[title].ErrorMessage = "Scrape failed";
                    break;
                default:
                    break;
            }
        }

        public ScraperState Get(MediaDataSet.TitlesRow title)
        {
            if (!activeScrapes.ContainsKey(title))
                return null;

            return activeScrapes[title];
        }

        public enum ScraperStatus
        {
            None,
            InProgress,
            MultipleResults,
            Error,
            Done
        }
        public class ScraperState
        {
            private string errorMessage = "";

            public string ErrorMessage
            {
                get { return errorMessage; }
                set { errorMessage = value; }
            }

            private Scraper scraper;

            public Scraper Scraper
            {
                get { return scraper; }
                set { scraper = value; }
            }
            private MediaDataSet.TitlesRow title;

            public MediaDataSet.TitlesRow Title
            {
                get { return title; }
                set { title = value; }
            }
            private ScraperStatus status;

            public ScraperStatus Status
            {
                get { return status; }
                set { status = value; }
            }

            public ScraperResult Result
            {
                get { if (results.Length > 0) return results[0]; else return null; }
            }

            private ScraperResult[] results;

            public ScraperResult[] Results
            {
                get { return results; }
                set { results = value; }
            }

            public ScraperState(Scraper s, MediaDataSet.TitlesRow title, ScraperStatus status)
            {
                this.scraper = s;
                this.title = title;
                this.status = status;
            }

        }

    }
}
